package org.sean.framework.web.filter;

import org.sean.framework.auth.token.JWT;
import org.sean.framework.util.DigestUtil;
import org.sean.framework.util.IPUtil;
import org.sean.framework.util.NumberUtil;
import org.sean.framework.util.ObjectUtil;
import org.sean.framework.util.StringUtil;
import org.springframework.core.NamedThreadLocal;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.util.LinkedCaseInsensitiveMap;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Map;

/**
 * 请求头处理器
 * HandlerInterceptor 为了在执行测试用例时,不用再指定Filter
 *
 * @author xielei
 */
public class HeaderFilter extends OncePerRequestFilter implements Ordered, HandlerInterceptor {

    /**
     * JWT
     */
    public static final String HEADER_JWT = "jwt";

    /**
     * 基于设备ID
     */
    public static final String HEADER_DEVICE_ID = "deviceId";
    /**
     * 基于客户端ID
     */
    public static final String HEADER_CLIENT_ID = "clientId";
    /**
     * 统计UV
     */
    public static final String HEADER_TARGET_ID = "targetID";
    /**
     * 基于用户IP灰度
     */
    public static final String HEADER_TARGET_IP = "targetIp";

    /**
     * 请求头
     */
    protected static final ThreadLocal<Map<String, String>> HEADERS = new NamedThreadLocal<>("Headers");
    /**
     * 平台
     * 0: 微链
     */
    private static final String HEADER_SOURCE = "source";
    /**
     * 业务来源
     * 1: 运营后台
     * 2: app
     * 3: 微信小程序
     * 4:
     */
    private static final String HEADER_PLATFORM = "pf";
    /**
     * 原始请求Host
     */
    private static final String HEADER_ORIGIN_API = "originApi";
    /**
     * 需要过滤的请求头
     */
    private static final LinkedCaseInsensitiveMap<String> FILTER_HEADERS = new LinkedCaseInsensitiveMap<>();

    /**
     * 请求属性 JWT
     */
    private static final ThreadLocal<JWT> ATTRIBUTES_JWT = new NamedThreadLocal<>("JWT");

    static {
        FILTER_HEADERS.put(HttpHeaders.HOST, null);
        FILTER_HEADERS.put(HttpHeaders.CONTENT_LENGTH, null);
        FILTER_HEADERS.put(HttpHeaders.TRANSFER_ENCODING, null);
        FILTER_HEADERS.put(HttpHeaders.ACCEPT_ENCODING, null);
        FILTER_HEADERS.put(HttpHeaders.RANGE, null);

    }

    /**
     * 处理 JWT
     *
     * @param request 请求
     */
    private static void handleJwt(HttpServletRequest request) {
        JWT jwt = JWT.createJWT(request.getHeader(HEADER_JWT));
        // 设置JWT
        ATTRIBUTES_JWT.set(jwt);
    }

    /**
     * UV
     *
     * @param request 请求
     * @param ip      ip
     * @return 返回标示ID
     */
    private static String getAccessID(HttpServletRequest request, String ip) {
        String accept = request.getHeader("accept");
        String agent = request.getHeader("user-agent");
        String acceptEncoding = request.getHeader("accept-encoding");
        return DigestUtil.md5Hex(accept + agent + acceptEncoding + ip);
    }

    /**
     * Return the Request Headers currently bound to the thread.
     *
     * @return the Request Headers currently bound to the thread,
     * or {@code null} if none bound
     */
    public Map<String, String> getHeaders() {
        Map<String, String> headers = HEADERS.get();
        if (headers == null) {
            synchronized (HeaderFilter.class) {
                headers = HEADERS.get();
                if (headers == null) {
                    headers = new LinkedCaseInsensitiveMap<>();
                }
                HEADERS.set(headers);
            }
        }
        return headers;
    }

    /**
     * 处理 请求头
     *
     * @param request 请求
     */
    private void handleHeader(HttpServletRequest request) {
        Map<String, String> headers = new LinkedCaseInsensitiveMap<>();
        Enumeration<String> headerNames = request.getHeaderNames();
        String value;
        String key;
        while (headerNames.hasMoreElements()) {
            key = headerNames.nextElement();
            if (FILTER_HEADERS.containsKey(key)) {
                continue;
            }
            value = request.getHeader(key);
            headers.put(key, value);
        }

        if (StringUtil.isEmpty(request.getHeader(HEADER_ORIGIN_API))) {
            // 保存原始请求API
            headers.put(HEADER_ORIGIN_API, request.getRequestURI());
        }
        String id = request.getHeader(HEADER_TARGET_ID);
        if (StringUtil.isEmpty(id)) {
            // 取ID
            headers.put(HEADER_TARGET_ID, getAccessID(request, id));
        }

        String remoteIp = request.getHeader(HEADER_TARGET_IP);
        if (StringUtil.isEmpty(remoteIp)) {
            // 取IP
            headers.put(HEADER_TARGET_IP, IPUtil.getRemoteIp(request));
        }

        handleJwt(request);
        getHeaders().putAll(headers);
    }


    /**
     * @return 取请求头中的JWT
     */
    public JWT getJWT() {
        return ATTRIBUTES_JWT.get();
    }

    /**
     * @return 取请求头中的JWT
     */
    public String getHeaderJWT() {
        return getHeaders().get(HEADER_JWT);
    }


    /**
     * @return 获取Collection Header
     */
    public Map<String, Collection<String>> getCollectionHeaders() {
        Map<String, Collection<String>> headers = new LinkedCaseInsensitiveMap<>();
        getHeaders().forEach((key, value) -> {
            Collection<String> set = headers.computeIfAbsent(key, k -> new HashSet<>());
            set.add(value);
        });
        return headers;
    }

    /**
     * @return 获取TargetID
     */
    public String getTargetID() {
        return getHeaders().get(HEADER_TARGET_ID);
    }

    /**
     * @return 获取来源
     */
    public int getSource() {
        return NumberUtil.getInteger(getHeaders().get(HEADER_SOURCE), 0);
    }

    /**
     * @return 获取平台
     */
    public int getPlatform() {
        return NumberUtil.getInteger(getHeaders().get(HEADER_PLATFORM), 0);
    }

    /**
     * @return 获取调用者IP
     */
    public String getRemoteIp() {
        return getHeaders().get(HEADER_TARGET_IP);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        handleHeader(request);
        filterChain.doFilter(request, response);
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (ObjectUtil.isEmpty(getHeaders())) {
            handleHeader(request);
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        HEADERS.remove();
        ATTRIBUTES_JWT.remove();
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 100;
    }
}
